## 15.4. A Complete Example

We spent some time trying to think of an example of a module that uses all the available hooks. At the same time, we spent considerable effort tracking through the innards of Apache to find out what happened when. Then we suddenly thought of writing a module to show what happened when. And, presto, mod_reveal.c was born. This is not a module you'd want to include in a live Apache without modification, since it prints stuff to the standard error output (which ends up in the error log, for the most part). But rather than obscure the main functionality by including code to switch the monitoring on and off, we thought it best to keep it simple. Besides, even in this form the module is very useful; it's presented and explained in this section.

### 15.4.1. Overview

The module implements two commands, `RevealServerTag` and `RevealTag`. `RevealServerTag` names a server section and is stored in the per-server configuration. `RevealTag` names a directory (or location or file) section and is stored in the per-directory configuration. When per-server or per-directory configurations are merged, the resulting configuration is tagged with a combination of the tags of the two merged sections. The module also implements a handler, which generates HTML with interesting information about a URL.

No self-respecting module starts without a copyright notice:

>     /*
>     Reveal the order in which things are done.

>     Copyright (C) 1996, 1998 Ben Laurie
>     */

Note that the included http_protocol.h is only needed for the request handler, the other two are required by almost all modules:

>     #include "httpd.h"
>     #include "http_config.h"
>     #include "http_protocol.h"

The per-directory configuration structure is:

>     typedef struct
>         {
>         char *szDir;
>         char *szTag;
>         } SPerDir;

And the per-server configuration structure is:

>     typedef struct
>         {
>         char *szServer;
>         char *szTag;
>         } SPerServer;

There is an unavoidable circular reference in most modules; the `module` structure is needed to access the per-server and per-directory configurations in the hook functions. But in order to construct the `module` structure, we need to know the hook functions. Since there is only one `module` structure and a lot of hook functions, it is simplest to forward reference the `module` structure:

>     extern module reveal_module;

If a string is `NULL`, it may crash `printf()` on some systems, so we define a function to give us a stand-in for `NULL` strings:

>     static const char *None(const char *szStr)
>         {
>         if(szStr)
>     	return szStr;
>         return "(none)";
>         }

Since the server names and port numbers are often not known when the per-server structures are created, but are filled in by the time the initialization function is called, we rename them in the `init` function. Note that we have to iterate over all the servers, since `init` is only called with the "main" server structure. As we go, we print the old and new names so we can see what is going on. Just for completeness, we add a module version string to the server version string. Note that you would not normally do this for such a minor module:

>     static void SubRevealInit(server_rec *pServer,pool *pPool)
>         {
>         SPerServer *pPerServer=ap_get_module_config(pServer->module_config,
>                                                     &reveal_module);

>         if(pServer->server_hostname &&
>            (!strncmp(pPerServer->szServer,"(none):",7)
>             || !strcmp(pPerServer->szServer+strlen(pPerServer->szServer)
>                        -2,":0")))
>         {
>             char szPort[20];

>             fprintf(stderr,"Init        : update server name from %s\n",
>                     pPerServer->szServer);
>             sprintf(szPort,"%d",pServer->port);
>             pPerServer->szServer=ap_pstrcat(pPool,pServer->server_hostname,":",
>                                             szPort,NULL);
>         }
>         fprintf(stderr,"Init        : host=%s port=%d server=%s tag=%s\n",
>                 pServer->server_hostname,pServer->port,pPerServer->szServer,
>                 None(pPerServer->szTag));
>         }

>     static void RevealInit(server_rec *pServer,pool *pPool)
>         {
>         ap_add_version_component("Reveal/0.0");
>         for( ; pServer ; pServer=pServer->next)
>             SubRevealInit(pServer,pPool);
>         fprintf(stderr,"Init        : done\n");
>         }

Here we create the per-server configuration structure. Since this is called as soon as the server is created, `pServer->server_hostname` and `pServer->port` may not have been initialized, so their values must be taken with a pinch of salt (but they get corrected later):

>     static void *RevealCreateServer(pool *pPool,server_rec *pServer)
>         {
>         SPerServer *pPerServer=ap_palloc(pPool,sizeof *pPerServer);
>         const char *szServer;
>         char szPort[20];

>         szServer=None(pServer->server_hostname);
>         sprintf(szPort,"%d",pServer->port);

>         pPerServer->szTag=NULL;
>         pPerServer->szServer=ap_pstrcat(pPool,szServer,":",szPort,NULL);

>         fprintf(stderr,"CreateServer: server=%s:%s\n",szServer,szPort);
>         return pPerServer;
>         }

Here we merge two per-server configurations. The merged configuration is tagged with the names of the two configurations from which it is derived (or the string `(none)` if they weren't tagged). Note that we create a new per-server configuration structure to hold the merged information (this is the standard thing to do):

>     static void *RevealMergeServer(pool *pPool,void *_pBase,void *_pNew)
>         {
>         SPerServer *pBase=_pBase;
>         SPerServer *pNew=_pNew;
>         SPerServer *pMerged=ap_palloc(pPool,sizeof *pMerged);

>         fprintf(stderr,
>               "MergeServer : pBase: server=%s tag=%s pNew: server=%s tag=%s\n",
>               pBase->szServer,None(pBase->szTag),
>               pNew->szServer,None(pNew->szTag));

>         pMerged->szServer=ap_pstrcat(pPool,pBase->szServer,"+",pNew->szServer,
>                                      NULL);
>         pMerged->szTag=ap_pstrcat(pPool,None(pBase->szTag),"+",
>                                   None(pNew->szTag),NULL);

>         return pMerged;
>         }

Now we create a per-directory configuration structure. If `szDir` is `NULL`, we change it to `(none)` to ensure that later merges have something to merge! Of course, `szDir` is `NULL` once for each server. Notice that we don't log which server this was created for; that's because there is no legitimate way to find out. It is also worth mentioning that this will only be called for a particular directory (or location or file) if a `RevealTag` directive occurs in that section:

>     static void *RevealCreateDir(pool *pPool,char *_szDir)
>         {
>         SPerDir *pPerDir=ap_palloc(pPool,sizeof *pPerDir);
>         const char *szDir=None(_szDir);

>         fprintf(stderr,"CreateDir   : dir=%s\n",szDir);

>         pPerDir->szDir=ap_pstrdup(pPool,szDir);
>         pPerDir->szTag=NULL;

>         return pPerDir;
>         }

Next we merge the per-directory structures. Again, we have no clue which server we are dealing with. In practice, you'll find this function is called a great deal:

>     static void *RevealMergeDir(pool *pPool,void *_pBase,void *_pNew)
>         {
>         SPerDir *pBase=_pBase;
>         SPerDir *pNew=_pNew;
>         SPerDir *pMerged=ap_palloc(pPool,sizeof *pMerged);

>         fprintf(stderr,"MergeDir    : pBase: dir=%s tag=%s "
>                 "pNew: dir=%s tag=%s\n",pBase->szDir,None(pBase->szTag),
>                 pNew->szDir,None(pNew->szTag));
>         pMerged->szDir=ap_pstrcat(pPool,pBase->szDir,"+",pNew->szDir,NULL);
>         pMerged->szTag=ap_pstrcat(pPool,None(pBase->szTag),"+",
>                                   None(pNew->szTag),NULL);

>         return pMerged;
>         }

Here is a helper function used by most of the other hooks to show the per-server and per-directory configurations currently in use. Although it caters to the situation in which there is no per-directory configuration, that should never happen:[87]

> [87]It happened while we were writing the module, because of a bug in the Apache core. We fixed the bug.

>     static void ShowRequestStuff(request_rec *pReq)
>         {
>         SPerDir *pPerDir=get_module_config(pReq->per_dir_config,
>                    &reveal_module);
>         SPerServer *pPerServer=get_module_config(pReq->server->
>                    module_config,&reveal_module);
>         SPerDir none={"(null)","(null)"};
>         SPerDir noconf={"(no per-dir config)","(no per-dir config)"};

>         if(!pReq->per_dir_config)
>             pPerDir=&noconf;
>         else if(!pPerDir)
>             pPerDir=&none;

>         fprintf(stderr," server=%s tag=%s dir=%s tag=%s\n",
>                 pPerServer->szServer,pPerServer->szTag,pPerDir->szDir,
>                    pPerDir->szTag);
>         }

None of the following hooks does anything more than trace itself:

>     static int RevealTranslate(request_rec *pReq)
>         {
>         fprintf(stderr,"Translate   : uri=%s",pReq->uri);
>         ShowRequestStuff(pReq);
>         return DECLINED;
>         }

>     static int RevealCheckUserID(request_rec *pReq)
>         {
>         fprintf(stderr,"CheckUserID :");
>         ShowRequestStuff(pReq);
>         return DECLINED;
>         }

>     static int RevealCheckAuth(request_rec *pReq)
>         {
>         fprintf(stderr,"CheckAuth   :");
>         ShowRequestStuff(pReq);
>         return DECLINED;
>         }

>     static int RevealCheckAccess(request_rec *pReq)
>         {
>         fprintf(stderr,"CheckAccess :");
>         ShowRequestStuff(pReq);
>         return DECLINED;
>         }

>     static int RevealTypeChecker(request_rec *pReq)
>         {
>         fprintf(stderr,"TypeChecker :");
>         ShowRequestStuff(pReq);
>         return DECLINED;
>         }

>     static int RevealFixups(request_rec *pReq)
>         {
>         fprintf(stderr,"Fixups      :");
>         ShowRequestStuff(pReq);
>         return DECLINED;
>         }

>     static int RevealLogger(request_rec *pReq)
>         {
>         fprintf(stderr,"Logger      :");
>         ShowRequestStuff(pReq);
>         return DECLINED;
>         }

>     static int RevealHeaderParser(request_rec *pReq)
>         {
>         fprintf(stderr,"HeaderParser:");
>         ShowRequestStuff(pReq);

>         return DECLINED;
>         }

Next comes the child initialization function. This extends the server tag to include the PID of the particular server instance it is in. Note that, like the `init` function, it must iterate through all the server instances:

>     static void RevealChildInit(server_rec *pServer, pool *pPool)
>         {
>         char szPID[20];

>         fprintf(stderr,"Child Init  : pid=%d\n",(int)getpid());

>         sprintf(szPID,"[%d]",(int)getpid());
>         for( ; pServer ; pServer=pServer->next)
>             {
>             SPerServer *pPerServer=ap_get_module_config(pServer->module_config,
>                                                         &reveal_module);
>             pPerServer->szServer=ap_pstrcat(pPool,pPerServer->szServer,szPID,
>                                             NULL);
>             }
>         }

Then the last two hooks are simply logged:

>     static void RevealChildExit(server_rec *pServer, pool *pPool)
>         {
>         fprintf(stderr,"Child Exit  : pid=%d\n",(int)getpid());
>         }

>     static int RevealPostReadRequest(request_rec *pReq)
>         {
>         fprintf(stderr,"PostReadReq : method=%s uri=%s protocol=%s",
>                 pReq->method,pReq->unparsed_uri,pReq->protocol);
>         ShowRequestStuff(pReq);

>         return DECLINED;
>         }

The following is the handler for the `RevealTag` directive. If more than one `RevealTag` appears in a section, they are glued together with a "-" separating them. A `NULL` is returned to indicate that there was no error:

>     static const char *RevealTag(cmd_parms *cmd, SPerDir *pPerDir, char *arg)
>         {
>         SPerServer *pPerServer=ap_get_module_config(cmd->server->module_config,
>                                                     &reveal_module);

>         fprintf(stderr,"Tag         : new=%s dir=%s server=%s tag=%s\n",
>                 arg,pPerDir->szDir,pPerServer->szServer,
>                 None(pPerServer->szTag));

>         if(pPerDir->szTag)
>             pPerDir->szTag=ap_pstrcat(cmd->pool,pPerDir->szTag,"-",arg,NULL);
>         else
>             pPerDir->szTag=ap_pstrdup(cmd->pool,arg);

>         return NULL;
>         }

This code handles the `RevealServerTag` directive. Again, if more than one `Reveal-ServerTag` appears in a server section they are glued together with "-" in between:

>     static const char *RevealServerTag(cmd_parms *cmd, SPerDir *pPerDir,
>                                        char *arg)
>         {
>         SPerServer *pPerServer=ap_get_module_config(cmd->server->module_config,
>                                                     &reveal_module);

>         fprintf(stderr,"ServerTag   : new=%s server=%s stag=%s\n",arg,
>                 pPerServer->szServer,None(pPerServer->szTag));

>         if(pPerServer->szTag)
>             pPerServer->szTag=ap_pstrcat(cmd->pool,pPerServer->szTag,"-",arg,
>                                          NULL);
>         else
>             pPerServer->szTag=ap_pstrdup(cmd->pool,arg);

>         return NULL;
>         }

Here we bind the directives to their handlers. Note that `RevealTag` uses `ACCESS_CONF|OR_ALL` as its `req_override` so that it is legal wherever a <`Directory`> section occurs. `RevealServerTag` only makes sense outside `<Directory`> sections, so it uses `RSRC_CONF`:

>     static command_rec aCommands[]=
>         {
>     { "RevealTag", RevealTag, NULL, ACCESS_CONF|OR_ALL, TAKE1, "a tag for this
>         section"},
>     { "RevealServerTag", RevealServerTag, NULL, RSRC_CONF, TAKE1, "a tag for this
>         server" },
>     { NULL }
>         };

These two helper functions simply output things as a row in a table:

>     static void TShow(request_rec *pReq,const char *szHead,const char *szItem)
>         {
>         rprintf(pReq,"<TR><TH>%s<TD>%s\n",szHead,szItem);
>         }

>     static void TShowN(request_rec *pReq,const char *szHead,int nItem)
>         {
>         rprintf(pReq,"<TR><TH>%s<TD>%d\n",szHead,nItem);
>         }

The following code is the request handler; it generates HTML describing the configurations that handle the URI:

>     static int RevealHandler(request_rec *pReq)
>         {
>         SPerDir *pPerDir=get_module_config(pReq->per_dir_config,
>                    &reveal_module);
>         SPerServer *pPerServer=get_module_config(pReq->server->
>                    module_config,&reveal_module);

>         pReq->content_type="text/html";
>         send_http_header(pReq);

>         rputs("<CENTER><H1>Revelation of ",pReq);
>         rputs(pReq->uri,pReq);
>         rputs("</H1></CENTER><HR>\n",pReq);
>         rputs("<TABLE>\n",pReq);
>         TShow(pReq,"URI",pReq->uri);
>         TShow(pReq,"Filename",pReq->filename);
>         TShow(pReq,"Server name",pReq->server->server_hostname);
>         TShowN(pReq,"Server port",pReq->server->port);
>         TShow(pReq,"Server config",pPerServer->szServer);
>         TShow(pReq,"Server config tag",pPerServer->szTag);
>         TShow(pReq,"Directory config",pPerDir->szDir);
>         TShow(pReq,"Directory config tag",pPerDir->szTag);
>         rputs("</TABLE>\n",pReq);

>         return OK;
>         }

Here we associate the request handler with the handler string:

>     static handler_rec aHandlers[]=
>         {
>     { "reveal", RevealHandler },
>     { NULL },
>         };

And finally, there is the `module` structure:

>     module reveal_module = {
>        STANDARD_MODULE_STUFF,
>        RevealInit,                  /* initializer */
>        RevealCreateDir,             /* dir config creater */
>        RevealMergeDir,              /* dir merger --- default is to override */
>        RevealCreateServer,          /* server config */
>        RevealMergeServer,           /* merge server configs */
>        aCommands,                   /* command table */
>        aHandlers,                   /* handlers */
>        RevealTranslate,             /* filename translation */
>        RevealCheckUserID,           /* check_user_id */
>        RevealCheckAuth,             /* check auth */
>        RevealCheckAccess,           /* check access */
>        RevealTypeChecker,           /* type_checker */
>        RevealFixups,                /* fixups */
>        RevealLogger,                /* logger */
>        RevealHeaderParser,          /* header parser */
>        RevealChildInit,             /* child init */
>        RevealChildExit,             /* child exit */
>        RevealPostReadRequest,       /* post read request */
>     };

The module can be included in Apache by specifying:

>     AddModule modules/extra/mod_reveal.o

in Configuration. You might like to try it on your favorite server: just pepper the httpd.conf file with `RevealTag` and `RevealServerTag` directives. Because of the huge amount of logging this produces, it would be unwise to use it on a live server!

### 15.4.2. Example Output

To illustrate mod_reveal.c in use, we used the following configuration:

>     Listen 9001
>     Listen 9000

>     TransferLog /home/ben/www/book/logs/access_log
>     ErrorLog /home/ben/www/book/logs/error_log
>     RevealTag MainDir
>     RevealServerTag MainServer
>     <LocationMatch /.reveal>
>     RevealTag Revealer
>     SetHandler reveal
>     </LocationMatch>

>     <VirtualHost :9001>
>     DocumentRoot /home/ben/www/docs
>     RevealTag H1Main
>     RevealServerTag H1
>     <Directory /home/ben/www/docs/protected>
>      RevealTag H1ProtectedDirectory
>     </Directory>
>     <Location /protected>
>      RevealTag H1ProtectedLocation
>     </Location>
>     </VirtualHost>

>     <VirtualHost :9000>
>     DocumentRoot /home/camilla/WWW/docs
>     RevealTag H2Main
>     RevealServerTag H2
>     </VirtualHost>

Note that the `<Directory>` and the `<Location>` sections in the first virtual host actually refer to the same place. This is to illustrate the order in which the sections are combined. Also note that the `<LocationMatch>` section doesn't have to correspond to a real file; looking at any location that ends with .reveal will invoke mod_reveal.c 's handler. Starting the server produces this on the screen:

>     bash$ httpd -d ~/www/book/
>     CreateServer: server=(none):0
>     CreateDir   : dir=(none)
>     Tag         : new=MainDir dir=(none) server=(none):0 tag=(none)
>     ServerTag   : new=MainServer server=(none):0 stag=(none)
>     CreateDir   : dir=/.reveal
>     Tag         : new=Revealer dir=/.reveal server=(none):0 tag=MainServer
>     CreateDir   : dir=(none)
>     CreateServer: server=(none):9001
>     Tag         : new=H1Main dir=(none) server=(none):9001 tag=(none)
>     ServerTag   : new=H1 server=(none):9001 stag=(none)
>     CreateDir   : dir=/home/ben/www/docs/protected
>     Tag         : new=H1ProtectedDirectory dir=/home/ben/www/docs/protected
>                   server=(none):9001 tag=H1
>     CreateDir   : dir=/protected
>     Tag         : new=H1ProtectedLocation dir=/protected server=(none):9001
>                   tag=H1
>     CreateDir   : dir=(none)
>     CreateServer: server=(none):9000
>     Tag         : new=H2Main dir=(none) server=(none):9000 tag=(none)
>     ServerTag   : new=H2 server=(none):9000 stag=(none)
>     MergeServer : pBase: server=(none):0 tag=MainServer pNew: server=(none):9000
>                   tag=H2
>     MergeDir    : pBase: dir=(none) tag=MainDir pNew: dir=(none) tag=H2Main
>     MergeServer : pBase: server=(none):0 tag=MainServer pNew: server=(none):9001
>                   tag=H1
>     MergeDir    : pBase: dir=(none) tag=MainDir pNew: dir=(none) tag=H1Main

Notice that the `<Location>` and `<LocationMatch>` sections are treated as directories as far as the code is concerned. At this point, `stderr` is switched to the error log, and the following is logged:

>     Init        : update server name from (none):0
>     Init        : host=freeby.ben.algroup.co.uk port=0
>                   server=freeby.ben.algroup.co.uk:0 tag=MainServer
>     Init        : update server name from (none):0+(none):9000
>     Init        : host=freeby.ben.algroup.co.uk port=9000
>                   server=freeby.ben.algroup.co.uk:9000 tag=MainServer+H2
>     Init        : update server name from (none):0+(none):9001
>     Init        : host=freeby.ben.algroup.co.uk port=9001
>                   server=freeby.ben.algroup.co.uk:9001 tag=MainServer+H1
>     Init        : done

At this point, the first-pass initialization is complete, and Apache destroys the configurations and starts again (this double initialization is required because directives may change things such as the location of the initialization files):[88]

> [88]You could argue that this procedure could lead to an infinite sequence of reinitializations. Well, in theory, it could, but in real life, Apache initializes twice, and that is that.

>     CreateServer: server=(none):0
>     CreateDir   : dir=(none)
>     Tag         : new=MainDir dir=(none) server=(none):0 tag=(none)
>     ServerTag   : new=MainServer server=(none):0 stag=(none)
>     CreateDir   : dir=/.reveal
>     Tag         : new=Revealer dir=/.reveal server=(none):0 tag=MainServer
>     CreateDir   : dir=(none)
>     CreateServer: server=(none):9001
>     Tag         : new=H1Main dir=(none) server=(none):9001 tag=(none)
>     ServerTag   : new=H1 server=(none):9001 stag=(none)
>     CreateDir   : dir=/home/ben/www/docs/protected
>     Tag         : new=H1ProtectedDirectory dir=/home/ben/www/docs/protected server=(none):9001 tag=H1
>     CreateDir   : dir=/protected
>     Tag         : new=H1ProtectedLocation dir=/protected server=(none):9001
>                   tag=H1
>     CreateDir   : dir=(none)
>     CreateServer: server=(none):9000
>     Tag         : new=H2Main dir=(none) server=(none):9000 tag=(none)
>     ServerTag   : new=H2 server=(none):9000 stag=(none)

Now we've created all the server and directory sections, and the top-level server is merged with the virtual hosts:

>     MergeServer : pBase: server=(none):0 tag=MainServer pNew: server=(none):9000
>                   tag=H2
>     MergeDir    : pBase: dir=(none) tag=MainDir pNew: dir=(none) tag=H2Main
>     MergeServer : pBase: server=(none):0 tag=MainServer pNew: server=(none):9001
>                   tag=H1
>     MergeDir    : pBase: dir=(none) tag=MainDir pNew: dir=(none) tag=H1Main

Now the `init` functions are called (which rename the servers now that their "real" names are known):

>     Init        : update server name from (none):0
>     Init        : host=freeby.ben.algroup.co.uk port=0
>                   server=freeby.ben.algroup.co.uk:0 tag=MainServer
>     Init        : update server name from (none):0+(none):9000
>     Init        : host=freeby.ben.algroup.co.uk port=9000
>                   server=freeby.ben.algroup.co.uk:9000 tag=MainServer+H2
>     Init        : update server name from (none):0+(none):9001
>     Init        : host=freeby.ben.algroup.co.uk port=9001
>                   server=freeby.ben.algroup.co.uk:9001 tag=MainServer+H1
>     Init        : done

Apache logs its startup message:

>     [Sun Jul 12 13:08:01 1998] [notice] Apache/1.3.1-dev (Unix) Reveal/0.0 configured -- resuming normal operations

`Child` `init`s are called:

>     Child Init  : pid=23287
>     Child Init  : pid=23288
>     Child Init  : pid=23289
>     Child Init  : pid=23290
>     Child Init  : pid=23291

And Apache is ready to start handling requests. First, we request http://host:9001/:

>     PostReadReq : method=GET uri=/ protocol=HTTP/1.0
>                   server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main
>     Translate   : uri=/ server=freeby.ben.algroup.co.uk:9001[23287]
>                   tag=MainServer+H1 dir=(none)+(none) tag=MainDir+H1Main
>     HeaderParser: server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main
>     CheckAccess : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main
>     TypeChecker : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main
>     Fixups      : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main

Because "/" is a directory, Apache attempts to use /index.html instead (in this case, it didn't exist, but Apache still goes through the motions):

>     Translate   : uri=/index.html server=freeby.ben.algroup.co.uk:9001[23287]
>                   tag=MainServer+H1 dir=(none)+(none) tag=MainDir+H1Main
>     CheckAccess : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main
>     TypeChecker : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main
>     Fixups      : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main
>     Logger      : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main
>     Child Init  : pid=23351

Pretty straightforward, but note that the configurations used are the merge of the main server's and the first virtual host's. Also notice the `child` `init` at the end: this is because Apache decided the load warranted starting another child to handle it.

Rather than go on at length, here's the most complicated request we can make: http://host:9001/protected/.reveal:

>     PostReadReq : method=GET uri=/protected/.reveal protocol=HTTP/1.0
>                   server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
>                   dir=(none)+(none) tag=MainDir+H1Main

After the Post Read Request phase, some merging is done on the basis of location:

>     MergeDir    : pBase: dir=(none)+(none) tag=MainDir+H1Main pNew: dir=/.reveal
>                   tag=Revealer
>     MergeDir    : pBase: dir=(none)+(none)+/.reveal tag=MainDir+H1Main+Revealer
>                   pNew: dir=/protected tag=H1ProtectedLocation

Then the URL is translated into a filename, using the newly merged directory configuration:

>     Translate   : uri=/protected/.reveal
>                   server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
>                   dir=(none)+(none)+/.reveal+/protected
>                   tag=MainDir+H1Main+Revealer+H1ProtectedLocation

Now that the filename is known, even more merging can be done. Notice that this time the section tagged as `H1ProtectedDirectory` is pulled in, too:

>     MergeDir    : pBase: dir=(none)+(none) tag=MainDir+H1Main pNew: dir=/home/
>                   ben/www/docs/protected tag=H1ProtectedDirectory
>     MergeDir    : pBase: dir=(none)+(none)+/home/ben/www/docs/protected
>                   tag=MainDir+H1Main+H1ProtectedDirectory pNew: dir=/.reveal
>                   tag=Revealer
>     MergeDir    : pBase: dir=(none)+(none)+/home/ben/www/docs/protected+/.reveal
>                   tag=MainDir+H1Main+H1ProtectedDirectory+Revealer pNew: dir=/
>                   protected tag=H1ProtectedLocation

And finally the request proceeds as usual:

>     HeaderParser: server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
>                   dir=(none)+(none)+/home/ben/www/docs/protected+/.reveal+/
>                   protected tag=MainDir+H1Main+H1ProtectedDirectory+
>                   Revealer+H1ProtectedLocation
>     CheckAccess : server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
>                   dir=(none)+(none)+/home/ben/www/docs/protected+/.reveal+/
>                   protected tag=MainDir+H1Main+H1ProtectedDirectory+
>                   Revealer+H1ProtectedLocation
>     TypeChecker : server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
>                   dir=(none)+(none)+/home/ben/www/docs/protected+/.reveal+/
>                   protected tag=MainDir+H1Main+H1ProtectedDirectory+
>                   Revealer+H1ProtectedLocation
>     Fixups      : server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
>                   dir=(none)+(none)+/home/ben/www/docs/protected+/.reveal+/
>                   protected tag=MainDir+H1Main+H1ProtectedDirectory+
>                   Revealer+H1ProtectedLocation
>     Logger      : server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
>                   dir=(none)+(none)+/home/ben/www/docs/protected+/.reveal+/
>                   protected tag=MainDir+H1Main+H1ProtectedDirectory+
>                   Revealer+H1ProtectedLocation

And there we have it. Although the merging of directories, locations, files, and so on gets rather hairy, Apache deals with it all for you, presenting you with a single server and directory configuration on which to base your code's decisions.

Copyright © 2001 O'Reilly & Associates. All rights reserved.